package org.biogroovy.uniprot

import groovy.util.logging.Slf4j

import javax.xml.parsers.DocumentBuilderFactory

import org.biogroovy.eutils.EUtilsURLFactory
import org.biogroovy.io.uniprot.UniProtReader;
import org.biogroovy.models.GeneOntology
import org.biogroovy.models.Protein
import org.biogroovy.search.AbstractSearchEngine
import org.biogroovy.search.IResultBuilder
import org.biogroovy.search.SearchException
import org.biogroovy.search.SearchParam
import org.biogroovy.search.SearchResult

/**
 * This search engine searches the UniProt Knowledge Base.
 *
 */
@Slf4j
class UniProtSearchEngine extends AbstractSearchEngine<SearchResult> {

	private static final String NAME = "UniProt";
	private static final String SHORTNAME = "UniProt";

	/**
	 * Constructor.
	 */
	public UniProtSearchEngine(){
		super();
		this.name = NAME;
		this.resultBuilder = new UniProtResultBuilder();
	}

	@Override
	public String getName() {
		return NAME;
	}


	@Override
	public String getURLTemplate() {
		return "http://www.uniprot.org/?"
	}

	@Override
	public List<SearchResult> doSearch(Map<String, String> parameters)
	throws SearchException {
		List<SearchResult> results = new ArrayList<>();

		// do the initial search
		def builder  = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		def root     = builder.parse(bind(parameters)).documentElement

		UniProtReader reader = new UniProtReader();
		List<String> idList = reader.parseList(root, "//Id");
		log.info "idList: " +idList;

		// fetch the articles
		String fetchURL = EUtilsURLFactory.getURL(EUtilsURLFactory.EFETCH, [db:EUtilsURLFactory.DB_GENE]);
		List<Protein> geneList = reader.readList(bind(fetchURL,[id:idList.join(","), retmode:'xml']));

		SearchResult result = null;
		IResultBuilder<Protein> resultBuilder = getResultBuilder();
		for(Protein gene: geneList){
			result = resultBuilder.convert(gene);
			results.add(result);
		}


		return results;

	}

	@Override
	protected void initSearchParams(){
		SearchParam term = new SearchParam(name:'query', isTerm: true, isRequired: true,isEditable: true);
		SearchParam accession = new SearchParam(name:'accession', isSubTerm:true, isRequired: false);
		SearchParam tax = new SearchParam(name:'taxonomy', isSubTerm:true);
		SearchParam tissue = new SearchParam(name:'interactor', isSubTerm:true);
		SearchParam format = new SearchParam(name:'format', isRequired:true, isEditable:false, value: 'xml');
		getSearchParameters().addAll(term, accession, tax, tissue, format)
	}
	


	/**
	 * This class is responsible for converting proteins into search results.
	 */
	class UniProtResultBuilder implements IResultBuilder<Protein>{
		
		/**
		 * Constructor.
		 */
		public UniProtResultBuilder(){
			
		}
		
		SearchResult<Protein> convert(Protein protein){
			SearchResult<Protein> result = new SearchResult([title:gene.symbol, description:gene.name]);
			result.url = URL + gene.getAccession();
			result.accession = gene.getAccession();
			result.tags = new ArrayList();
			
			gene.goComponentList.each{GeneOntology goTerm ->
				if (goTerm.name != null && goTerm.name != ""){
					result.tags.add(goTerm.name);
				}
			}

			gene.goFunctionList.each{GeneOntology goTerm ->
				if (goTerm.name != null && goTerm.name != ""){
					result.tags.add(goTerm.name);
				}
			}

			gene.goProcessList.each{GeneOntology goTerm ->
				if (goTerm.name != null && goTerm.name != ""){
					result.tags.add(goTerm.name);
				}
			}
			
			result.setResult(gene);
			return result;
		}
	}

}
